package org.amse.korovkin.ciphering.model;

import org.amse.korovkin.ciphering.model.cipher.monocipher.ChangeTable;
import java.io.*;
import java.util.*;
import org.amse.korovkin.ciphering.Main;

public class Analyzator {

    private static HashSet<String> dictionary = new HashSet<String>();
    private static final String DICTIONARY_PATH = "org/amse/korovkin/ciphering/eng.dic";
    private static boolean existDictionary = false;
    // FILE_THRESHOLD - Value of penalty that can not be passed in method analyse
    private static final int FILE_THRESHOLD = 10;
    // Threshold for amount of symbols to analyse
    private static final int LENGTH_THRESHOLD = 10000;
    /**
     * The best value of Penalty to encrypted text.
     * @see #analyze(java.lang.String) 
     */
    private static int minPenalty = Integer.MAX_VALUE;
     /**
     * The best value of BigramPenalty to Table of Bigram.
     * @see org.amse.miha.ciphering.BigramFrequency#compare(BigramFrequency standart, BigramFrequency current)
     */
    public static double minBiPenalty = Double.MAX_VALUE;

    public static void setMinPenalty(int penalty) {
        minPenalty = penalty;
    }
    public static void setMinBiPenalty(double penalty) {
        minBiPenalty = penalty;
    }

    // Read dictionary from file with path {@code DICTIONARY}
    private static HashSet<String> getDictionary()
            throws IOException {
        HashSet<String> dictionary = new HashSet<String>();
        InputStream is = Main.class.getClassLoader().getResourceAsStream(DICTIONARY_PATH);
        Scanner sc = new Scanner(is);
        while (sc.hasNextLine()) {
            String s = sc.nextLine();
            String[] subString = s.split("/");
            dictionary.add(subString[0]);
        }
        sc.close();
        return dictionary;
    }

    // Find length (amount of symbols) of file
    private static int findLength(String inFileName)
            throws IOException {
        int i;
        int fileLength = 0;
        FileReader fr = new FileReader(inFileName);
        while ((i = fr.read()) != -1) {
            fileLength++;
        }
        fr.close();
        return fileLength;
    }

    /**
     * Analyse the text in file with path {@code inFile}.
     * Find English words in text and compound penalty for not English words.
     * If penalty is very big, return -1.
     * @param inFile Name of path to File with text.
     * @return Penalty (integer)
     * @throws java.io.IOException
     */
    public static int analyze(String inFile)
            throws IOException {
        if (!existDictionary) {
            dictionary = getDictionary();
            existDictionary = true;
        }
        FileReader fr = new FileReader(inFile);
        int i;
        int penalty = 0;
        int fileLength = findLength(inFile);
        StringBuilder sb = new StringBuilder();
        int counter = 0;
        while ((i = fr.read()) != -1) {
            counter++;
            char symbol = (char) i;
            if ((symbol >= 'a' && symbol <= 'z') || (symbol >= 'A' && symbol <= 'Z')) {
                sb.append(symbol);
            } else {
                if (sb.length() != 0) {
                    String s = sb.toString();
                    if (sb.charAt(0) >= 'A' && sb.charAt(0) <= 'Z') {                        
                        char smallFirst = ChangeTable.toLowerCase(sb.charAt(0));
                        sb.delete(0, 1);
                        sb.insert(0, smallFirst);
                        String smallS = sb.toString();
                        sb.delete(0, sb.length());
                        if (!(dictionary.contains(s) || dictionary.contains(smallS))) {
                            penalty++;
                        }
                    } else {
                        sb.delete(0, sb.length());
                        if (!dictionary.contains(s)) {
                            penalty++;
                        }
                    }
                }
            }
            if (penalty > Math.min(fileLength, LENGTH_THRESHOLD) / FILE_THRESHOLD
                    || penalty > minPenalty) {
                fr.close();
                return -1;
            }
            if (counter > LENGTH_THRESHOLD) {
                break;
            }
        }
        fr.close();
        return penalty;
    }

    
}
